#ifndef __MT_MD_H__
#define __MT_MD_H__

#include <stddef.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <setjmp.h>
#include <pthread.h>

#include "mthread.h"

#define MD_SETJMP(env) _setjmp(env)
#define MD_LONGJMP(env, val) _longjmp(env, val)

#define MD_JB_SP   2

#define MT_BEGIN_MACRO  {
#define MT_END_MACRO    }


#define MD_INIT_CONTEXT(_thread, _sp, _main)          \
  MT_BEGIN_MACRO                                      \
  if (MD_SETJMP((_thread)->context))                  \
    _main();                                          \
  (_thread)->context[0]._jb[MD_JB_SP] = (long) (_sp); \
  MT_END_MACRO

#ifndef MD_STACK_PAD_SIZE
#define MD_STACK_PAD_SIZE 128
#endif

#define MT_INSERT_BEFORE(_e,_l)	 \
				 MT_BEGIN_MACRO		 \
				 (_e)->next = (_l);	 \
				 (_e)->prev = (_l)->prev; \
				 (_l)->prev->next = (_e); \
				 (_l)->prev = (_e);	 \
				 MT_END_MACRO

				 /* Insert element "_e" into the list, after "_l" */
#define MT_INSERT_AFTER(_e,_l)	 \
				 MT_BEGIN_MACRO		 \
				 (_e)->next = (_l)->next; \
				 (_e)->prev = (_l);	 \
				 (_l)->next->prev = (_e); \
				 (_l)->next = (_e);	 \
				 MT_END_MACRO

				 /* Return the element following element "_e" */
#define MT_NEXT_LINK(_e)  ((_e)->next)

				 /* Append an element "_e" to the end of the list "_l" */
#define MT_APPEND_LINK(_e,_l) MT_INSERT_BEFORE(_e,_l)

				 /* Insert an element "_e" at the head of the list "_l" */
#define MT_INSERT_LINK(_e,_l) MT_INSERT_AFTER(_e,_l)

				 /* Return the head/tail of the list */
#define MT_LIMT_HEAD(_l) (_l)->next
#define MT_LIMT_TAIL(_l) (_l)->prev

				 /* Remove the element "_e" from it's circular list */
#define MT_REMOVE_LINK(_e)	       \
				 MT_BEGIN_MACRO		       \
				 (_e)->prev->next = (_e)->next; \
				 (_e)->next->prev = (_e)->prev; \
				 MT_END_MACRO

				 /* Return non-zero if the given circular list "_l" is empty, */
				 /* zero if the circular list is not empty */
#define MT_CLIMT_IS_EMPTY(_l) \
				 ((_l)->next == (_l))

				 /* Initialize a circular list */
#define MT_INIT_CLIST(_l)  \
				 MT_BEGIN_MACRO	   \
				 (_l)->next = (_l); \
				 (_l)->prev = (_l); \
				 MT_END_MACRO

#define MT_INIT_STATIC_CLIST(_l) \
				 {(_l), (_l)}
				 
				 typedef struct _mt_thread _mt_thread_t;

				 typedef struct _mt_vp {
					 _mt_thread_t *prim;
					 _mt_thread_t *run_q;      
					 pthread_t 	 pself;
					 int pagesize;
				 } _mt_vp_t;

/*****************************************
				 * Current vp, thread, and event system
 */

				 extern _mt_vp_t	    _mt_this_vp[16];
				 extern _mt_thread_t *_mt_this_thread[16];

#define _MT_CURRENT_THREAD(i)            (_mt_this_thread[i])
#define _MT_SET_CURRENT_THREAD(_thread, i) (_mt_this_thread[i] = (_thread))

#define _MT_RUNQ(i)                        (_mt_this_vp[i].run_q)
#define _MT_PAGE_SIZE(i)                   (_mt_this_vp[i].pagesize)


/*****************************************
				 * vp queues operations
 */
#define _MT_ADD_RUNQ(_thr, i)  MT_APPEND_LINK(&(_thr)->links, _MT_RUNQ(i))
#define _MT_DEL_RUNQ(_thr)  MT_REMOVE_LINK(&(_thr)->links)
/*****************************************
				 * Thread states and flags
 */

#define _MT_FL_PRIMORDIAL   0x01
#define _MT_FL_IDLE_THREAD  0x02
#define _MT_FL_ON_SLEEPQ    0x04
#define _MT_FL_INTERRUPT    0x08
#define _MT_FL_TIMEDOUT     0x10


/*****************************************
				 * Pointer conversion
 */

#ifndef offsetof
#define offsetof(type, identifier) ((size_t)&(((type *)0)->identifier))
#endif

#define _MT_THREAD_PTR(_qp)         \
				 ((_mt_thread_t *)((char *)(_qp) - offsetof(_mt_thread_t, links)))

#define _MT_THREAD_STACK_PTR(_qp)   \
				 ((_mt_stack_t *)((char*)(_qp) - offsetof(_mt_stack_t, links)))

/*****************************************
				 * Constants
 */

#define MT_DEFAULT_STACK_SIZE (64*1024)

#ifndef MT_KEYS_MAX
#define MT_KEYS_MAX 16
#endif

#define _MT_RESTORE_CONTEXT(_thread, vp)   \
				 MT_BEGIN_MACRO                     \
				 _MT_SET_CURRENT_THREAD(_thread, vp);   \
				 MD_LONGJMP((_thread)->context, 1); \
				 MT_END_MACRO

/*
				 * Initialize the thread context preparing it to execute _main
 */
#define _MT_INIT_CONTEXT MD_INIT_CONTEXT

/*
				 * Number of bytes reserved under the stack "bottom"
 */
#define _MT_STACK_PAD_SIZE MD_STACK_PAD_SIZE


/*****************************************
				 * Forward declarations
 */

				 _mt_stack_t *_mt_stack_new(uint32_t stack_size);
				 void _mt_stack_free(_mt_stack_t *ts);	 
#endif /* !__MT_COMMON_H__ */

